﻿namespace EFS.RC.CC.Tools.Deployment.Update
{
	/// <summary>
	/// DomainUsers update
	/// </summary>
	internal class DomainUsers : EFS.Common.Async.AsyncRoot
	{
		#region Composition

		// sync access
		private object syncAccess = new object();

		// domain
		private EFS.AD.Domain domain = null;

		/// <summary>
		/// Status
		/// </summary>
		public enum UpdateStatus { Idle, Executed }

		// Status
		private UpdateStatus status = UpdateStatus.Idle;

		#endregion

		#region Constructor
		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="conversation"></param>
		/// <param name="remoteEndpoint"></param>
		public DomainUsers(EFS.AD.Domain domain)
		{
			//check
			EFS.Common.Verify.Reference(domain, "domain");

			// set
			this.domain = domain;

			// log
			EFS.EventLog.Log.LogInfo("DomainUsers", this);
		}

		#endregion

		#region Usage

		/// <summary>
		/// Describe this object into a nice formated string
		/// </summary>
		/// <returns></returns>
		public override System.String Describe()
		{
			return System.String.Format("EFS.RC.CC.Tools.Deployment.Update.DomainUsers");
		}

		/// <summary>
		/// Begin startup
		/// </summary>
		public EFS.Common.Async.AsyncProcess Execute()
		{
			// log
			EFS.EventLog.Log.LogInfo("BeginStartup", this);

			// start
			return BeginAsyncProcess2(ExecuteUpdate, OnExecuteUpdateComplete);
		}

		#endregion

		#region Runtime

		/// <summary>
		/// Unhandled exception
		/// </summary>
		/// <param name="ex"></param>
		protected override void OnException(System.Exception ex)
		{
			// check
			EFS.Common.Verify.Reference(ex, "ex");

			// log
			EFS.EventLog.Log.LogException(ex, this);

			// SAL
			EFS.RC.CC.Tools.Loggers.SAL.Add(null, "OnException", ex, this);
		}

		#endregion

		#region Execute

		/// <summary>
		/// Startup
		/// </summary>
		private void ExecuteUpdate()
		{
			// log
			EFS.EventLog.Log.LogInfo("ExecuteUpdate", this);

			// sync access
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				if (status != UpdateStatus.Idle)
				{
					throw new System.InvalidOperationException("Only Idle Update can be started");
				}

				// started
				status = UpdateStatus.Executed;
			}

			// create or delete
			foreach (AD.User user in domain)
			{
				try
				{
					// update to database
					EFS.RC.CC.CH.Tables.ADUsers.CreateIfNotExists(
						user.ObjectGuid, user.LogonName, user.FirstName, user.LastName);
				}
				catch (System.Exception ex)
				{
					// log
					EFS.EventLog.Log.LogException(ex, this);
	
					// log data
					EFS.EventLog.Log.LogWarning(System.String.Format("Failed to update/create user id= {0}; logon= {1}; name= {2}; {3}", user.ObjectGuid, user.LogonName, user.FirstName, user.LastName), this);
				}
			}
		}

		/// <summary>
		/// ExecuteUpdate complete
		/// </summary>
		/// <param name="ar"></param>
		private void OnExecuteUpdateComplete(EFS.Common.Async.AsyncProcess ap)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnExecuteUpdateComplete", this);

			try
			{
				// check
				ap.Throw();

				// log
				EFS.EventLog.Log.LogInfo("OnExecuteUpdateComplete SUCCCESS", this);
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);
			}
		}

		#endregion
	}
}
